package vm


import "api"


const LFIELDS_PER_FLUSH = 50


// `NEWTABLE`指令(`iABC`模式)创建空表，并将其放入指定寄存器
// 寄存器索引由操作数A指定，表的初始数组容量和哈希表容量分别由操作数B和C指定
// R(A) := {} (size = B,C)
func newTable(i Instruction, vm api.LuaVM) {

	a, b, c := i.ABC()

	a += 1

	vm.CreateTable(Fb2Int(b), Fb2Int(c))
	vm.Replace(a)
}


// `GETTABLE`指令(`iABC`模式)根据键从表里取值，并放入目标寄存器中
// 其中表位于寄存器中，索引由操作数B指定
// 键可能位于寄存器中，也可能在常量表里，索引由操作数C指定
// 目标寄存器索引则由操作数A指定
// R(A) := R(B)[RK(C)]
func getTable(i Instruction, vm api.LuaVM) {

	a, b, c := i.ABC()
	a += 1
	b += 1

	vm.GetRK(c)
	vm.GetTable(b)
	vm.Replace(a)
}


// `SETTABLE`指令(`iABC`模式)根据键往表里赋值
// 其中标卫浴寄存器中，索引由操作数A指定
// 键和值可能位于寄存器中，也可能在常量表里，索引分别由操作数B和C指定
func setTable(i Instruction, vm api.LuaVM) {

	a, b, c := i.ABC()
	a += 1

	vm.GetRK(b)
	vm.GetRK(c)
	vm.SetTable(a)
}


// `SETLIST`指令(`iABC`模式)则是专门给数组准备的，用于按索引批量设置数组元素
// 其中数组位于寄存器中，索引由操作数A指定
// 需要写入数组的一系列值也在寄存器中，紧挨着数组，数量由操作数B指定
// 数组起始索引则由操作数C指定
// R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
func setList(i Instruction, vm api.LuaVM) {

	a, b, c := i.ABC()
	a += 1

	if c > 0 {
		c = c - 1
	} else {
		c = Instruction(vm.Fetch()).Ax()
	}

	bIsZero := b == 0
	if bIsZero {
		b = int(vm.ToInteger(-1)) - a - 1
		vm.Pop(1)
	}

	vm.CheckStack(1)
	idx := int64(c * LFIELDS_PER_FLUSH)
	for j := 1; j <= b; j++ {
		idx++
		vm.PushValue(a + j)
		vm.SetI(a, idx)
	}


	if bIsZero {
		for j := vm.RegisterCount() + 1; j <= vm.GetTop(); j++ {
			idx++
			vm.PushValue(j)
			vm.SetI(a, idx)
		}

		vm.SetTop(vm.RegisterCount())  // clear stack
	}
}